home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / answers / comp / motif-faq / part3 < prev    next >
Text File  |  1994-04-14  |  51KB  |  1,329 lines

  1. Path: bloom-beacon.mit.edu!hookup!swrinde!cs.utexas.edu!howland.reston.ans.net!europa.eng.gtefsd.com!news.umbc.edu!cs.umd.edu!kong.gsfc.nasa.gov!kong.gsfc.nasa.gov!not-for-mail
  2. From: dealy@kong.gsfc.nasa.gov (Brian Dealy)
  3. Newsgroups: comp.windows.x.motif,news.answers,comp.answers
  4. Subject: Motif FAQ (Part 3 of 5)
  5. Followup-To: poster
  6. Date: 14 Apr 1994 15:20:35 -0400
  7. Organization: NASA/Goddard Space Flight Center
  8. Lines: 1311
  9. Approved: news-answers-request@MIT.Edu
  10. Distribution: inet
  11. Expires: +1 months
  12. Message-ID: <2ok523$5em@kong.gsfc.nasa.gov>
  13. Reply-To: dealy@kong.gsfc.nasa.gov (Brian Dealy)
  14. NNTP-Posting-Host: kong.gsfc.nasa.gov
  15. Keywords: FAQ question answer
  16. Xref: bloom-beacon.mit.edu comp.windows.x.motif:15727 news.answers:18059 comp.answers:4910
  17.  
  18. Archive-name: motif-faq/part3
  19. Last-modified: APR 04, 1994
  20. Version: 3.6
  21.  
  22.  
  23.  
  24.  
  25.  
  26.  
  27.  
  28. -----------------------------------------------------------------------------
  29. Subject: 62)  TOPIC: FORM WIDGET
  30.  
  31.  
  32. -----------------------------------------------------------------------------
  33. Subject: 63)  Why don't labels in a Form resize when the label is changed?
  34. I've got some labels in a form. The labels don't resize whenever the label
  35. string resource is changed. As a result, the operator has to resize the window
  36. to see the new label contents. I am using Motif 1.1.
  37.  
  38. Answer: This problem may happen to any widget inside a Form widget. The
  39. problem was that the Form will resize itself when it gets geometry requests
  40. from its children. If its preferred size is not allowed, the Form will
  41. disallow all geometry requests from its children. The workaround is that you
  42. should set any ancestor of the Form to be resizable. For the shell which
  43. contains the Form you should set the shell resource XmNallowShellResize to be
  44. True (by default, it is set to FALSE).  There is currently an inconsistency on
  45. how resizing is being done, and it may get fixed in Motif 1.2.
  46.  
  47. From db@sunbim.be (Danny Backx)
  48.  
  49. Basically what you have to do is set the XmNresizePolicy on the Form to
  50. XmRESIZE_NONE.  The facts seem to be that XmRESIZE_NONE does NOT mean "do not
  51. allow resizes".  You may also have to set XmNresizable on the form to True.
  52.  
  53. -----------------------------------------------------------------------------
  54. Subject: 64)  How can I center a widget in a form?
  55.  
  56. Answer: One of Motif's trickier questions.  The problems are that: Form gives
  57. no support for centering, only for edge attachments, and the widget must stay
  58. in the center if the form or the widget is resized.  Just looking at
  59. horizontal centering (vertical is similar) some solutions are:
  60.  
  61.  a.  Use the table widget instead of Form.
  62.  
  63.  b.  A hack free solution is from Dan Heller:
  64.  
  65.      /* Written by Dan Heller.  Copyright 1991, O'Reilly && Associates.
  66.       * This program is freely distributable without licensing fees and
  67.       * is provided without guarantee or warranty expressed or implied.
  68.       * This program is -not- in the public domain.  This program is
  69.       * taken from the Motif Programming Manual, O'Reilly Volume 6.
  70.       */
  71.  
  72.      /* corners.c -- demonstrate widget layout management for a
  73.       * BulletinBoard widget.  There are four widgets each labeled
  74.       * top-left, top-right, bottom-left and bottom-right.  Their
  75.       * positions in the bulletin board correspond to their names.
  76.       * Only when the widget is resized does the geometry management
  77.       * kick in and position the children in their correct locations.
  78.       */
  79.      #include <Xm/BulletinB.h>
  80.      #include <Xm/PushBG.h>
  81.  
  82.      char *corners[] = {
  83.          "Top-Left", "Top-Right", "Bottom-Left", "Bottom-Right",
  84.      };
  85.  
  86.      static void resize();
  87.  
  88.      main(argc, argv)
  89.      int argc;
  90.      char *argv[];
  91.      {
  92.          Widget toplevel, bboard;
  93.          XtAppContext app;
  94.          XtActionsRec rec;
  95.          int i;
  96.  
  97.          /* Initialize toolkit and create toplevel shell */
  98.          toplevel = XtVaAppInitialize(&app, "Demos", NULL, 0,
  99.              &argc, argv, NULL, NULL);
  100.  
  101.          /* Create your standard BulletinBoard widget */
  102.          bboard = XtVaCreateManagedWidget("bboard",
  103.              xmBulletinBoardWidgetClass, toplevel, NULL);
  104.  
  105.          /* Set up a translation table that captures "Resize" events
  106.           * (also called ConfigureNotify or Configure events).  If the
  107.           * event is generated, call the function resize().
  108.           */
  109.          rec.string = "resize";
  110.          rec.proc = resize;
  111.          XtAppAddActions(app, &rec, 1);
  112.          XtOverrideTranslations(bboard,
  113.              XtParseTranslationTable("<Configure>: resize()"));
  114.  
  115.          /* Create children of the dialog -- a PushButton in each corner. */
  116.          for (i = 0; i < XtNumber(corners); i++)
  117.              XtVaCreateManagedWidget(corners[i],
  118.                  xmPushButtonGadgetClass, bboard, NULL);
  119.  
  120.          XtRealizeWidget(toplevel);
  121.          XtAppMainLoop(app);
  122.      }
  123.  
  124.      /* resize(), the routine that is automatically called by Xt upon the
  125.       * delivery of a Configure event.  This happens whenever the widget
  126.       * gets resized.
  127.       */
  128.      static void
  129.      resize(w, event, args, num_args)
  130.      CompositeWidget w;   /* The widget (BulletinBoard) that got resized */
  131.      XConfigureEvent *event;  /* The event struct associated with the event */
  132.      String args[]; /* unused */
  133.      int *num_args; /* unused */
  134.      {
  135.          WidgetList children;
  136.          int width = event->width;
  137.          int height = event->height;
  138.          Dimension w_width, w_height;
  139.          short margin_w, margin_h;
  140.  
  141.          /* get handle to BulletinBoard's children and marginal spacing */
  142.          XtVaGetValues(w,
  143.              XmNchildren, &children,
  144.              XmNmarginWidth, &margin_w,
  145.              XmNmarginHeight, &margin_h,
  146.              NULL);
  147.  
  148.          /* place the top left widget */
  149.          XtVaSetValues(children[0],
  150.              XmNx, margin_w,
  151.  
  152.              XmNy, margin_h,
  153.              NULL);
  154.  
  155.          /* top right */
  156.          XtVaGetValues(children[1], XmNwidth, &w_width, NULL);
  157.  
  158.          /* To Center a widget in the middle of the BulletinBoard (or Form),
  159.           * simply call:
  160.           *   XtVaSetValues(widget,
  161.                XmNx,    (width - w_width)/2,
  162.                XmNy,    (height - w_height)/2,
  163.                NULL);
  164.           * and return.
  165.           */
  166.          XtVaSetValues(children[1],
  167.              XmNx, width - margin_w - w_width,
  168.              XmNy, margin_h,
  169.              NULL);
  170.          /* bottom left */
  171.          XtVaGetValues(children[2], XmNheight, &w_height, NULL);
  172.          XtVaSetValues(children[2],
  173.  
  174.              XmNx, margin_w,
  175.              XmNy, height - margin_h - w_height,
  176.              NULL);
  177.          /* bottom right */
  178.          XtVaGetValues(children[3],
  179.              XmNheight, &w_height,
  180.              XmNwidth, &w_width,
  181.              NULL);
  182.          XtVaSetValues(children[3],
  183.              XmNx, width - margin_w - w_width,
  184.              XmNy, height - margin_h - w_height,
  185.              NULL);
  186.      }
  187.  
  188.  c.  No uil solution has been suggested, because of the widget size problem
  189.  
  190. -----------------------------------------------------------------------------
  191. Subject: 65)  How do I line up two columns of widgets of different types?  I
  192. have a column of say label widgets, and a column of text widgets and I want to
  193. have them lined up horizontally. The problem is that they are of different
  194. heights. Just putting them in a form or rowcolumn doesn't line them up
  195. properly because the label and text widgets are of different height.
  196.  
  197. If you want the geometry to look like this
  198.  
  199.           -------------------------------------
  200.          |          -------------------------- |
  201.          |a label  |Some text                 ||
  202.          |          -------------------------- |
  203.                            ------------------- |
  204.          |a longer label  |Some more text     ||
  205.          |                 ------------------- |
  206.          |                    ---------------- |
  207.          |a very long label  |Even more text  ||
  208.          |                    ---------------- |
  209.           -------------------------------------
  210.  
  211. try
  212.  
  213. /* Written by Dan Heller.  Copyright 1991, O'Reilly && Associates.
  214.  * This program is freely distributable without licensing fees and
  215.  * is provided without guarantee or warranty expressed or implied.
  216.  * This program is -not- in the public domain.  This program is
  217.  * taken from the Motif Programming Manual, O'Reilly Volume 6.
  218.  */
  219.  
  220. /* text_form.c -- demonstrate how attachments work in Form widgets.
  221.  * by creating a text-entry form type application.
  222.  */
  223.  
  224. #include <Xm/PushB.h>
  225. #include <Xm/PushBG.h>
  226. #include <Xm/LabelG.h>
  227. #include <Xm/Text.h>
  228. #include <Xm/Form.h>
  229.  
  230. char *prompts[] = {
  231.     "Name:", "Phone:", "Address:",
  232.     "City:", "State:", "Zip:",
  233. };
  234.  
  235. main(argc, argv)
  236. int argc;
  237. char *argv[];
  238. {
  239.     Widget toplevel, mainform, subform, label, text;
  240.     XtAppContext app;
  241.     char buf[32];
  242.     int i;
  243.  
  244.     toplevel = XtVaAppInitialize(&app, "Demos", NULL, 0,
  245.         &argc, argv, NULL, NULL);
  246.  
  247.     mainform = XtVaCreateWidget("mainform",
  248.         xmFormWidgetClass, toplevel,
  249.         NULL);
  250.  
  251.     for (i = 0; i < XtNumber(prompts); i++) {
  252.         subform = XtVaCreateWidget("subform",
  253.             xmFormWidgetClass,   mainform,
  254.             /* first one should be attached for form */
  255.             XmNtopAttachment,    i? XmATTACH_WIDGET : XmATTACH_FORM,
  256.             /* others are attached to the previous subform */
  257.             XmNtopWidget,        subform,
  258.             XmNleftAttachment,   XmATTACH_FORM,
  259.             XmNrightAttachment,  XmATTACH_FORM,
  260.             NULL);
  261.         label = XtVaCreateManagedWidget(prompts[i],
  262.             xmLabelGadgetClass,  subform,
  263.             XmNtopAttachment,    XmATTACH_FORM,
  264.             XmNbottomAttachment, XmATTACH_FORM,
  265.             XmNleftAttachment,   XmATTACH_FORM,
  266.             XmNalignment,        XmALIGNMENT_BEGINNING,
  267.             NULL);
  268.         sprintf(buf, "text_%d", i);
  269.         text = XtVaCreateManagedWidget(buf,
  270.             xmTextWidgetClass,   subform,
  271.             XmNtopAttachment,    XmATTACH_FORM,
  272.             XmNbottomAttachment, XmATTACH_FORM,
  273.             XmNrightAttachment,  XmATTACH_FORM,
  274.             XmNleftAttachment,   XmATTACH_WIDGET,
  275.             XmNleftWidget,       label,
  276.             NULL);
  277.         XtManageChild(subform);
  278.     }
  279.     /* Now that all the forms are added, manage the main form */
  280.     XtManageChild(mainform);
  281.  
  282.     XtRealizeWidget(toplevel);
  283.     XtAppMainLoop(app);
  284. }
  285.  
  286. If you resize horizontally it stretches the text widgets.  If you resize
  287. vertically it leaves space under the bottom (if you don't resize, this is not
  288. problem).
  289.  
  290. If you want the text widgets to be lined up on the left, as in
  291.  
  292.           ----------------------------------------
  293.          |                    ------------------- |
  294.          |          a label  |Some text          ||
  295.          |                    ------------------- |
  296.                               ------------------- |
  297.          |   a longer label  |Some more text     ||
  298.          |                    ------------------- |
  299.          |                    ------------------- |
  300.          |a very long label  |Even more text     ||
  301.          |                    ------------------- |
  302.           ----------------------------------------
  303.  
  304. try this
  305.  
  306. /* Written by Dan Heller.  Copyright 1991, O'Reilly && Associates.
  307.  * This program is freely distributable without licensing fees and
  308.  * is provided without guarantee or warranty expressed or implied.
  309.  * This program is -not- in the public domain.  This program is
  310.  * taken from the Motif Programming Manual, O'Reilly Volume 6.
  311.  */
  312.  
  313. /* text_entry.c -- This demo shows how the RowColumn widget can be
  314.  * configured to build a text entry form.  It displays a table of
  315.  * right-justified Labels and Text widgets that extend to the right
  316.  * edge of the Form.
  317.  */
  318. #include <Xm/LabelG.h>
  319. #include <Xm/RowColumn.h>
  320. #include <Xm/Text.h>
  321.  
  322. char *text_labels[] = {
  323.     "Name:", "Phone:", "Address:", "City:", "State:", "Zip:",
  324. };
  325.  
  326. main(argc, argv)
  327. int argc;
  328. char *argv[];
  329. {
  330.     Widget toplevel, rowcol;
  331.     XtAppContext app;
  332.     char buf[8];
  333.     int i;
  334.  
  335.     toplevel = XtVaAppInitialize(&app, "Demos", NULL, 0,
  336.         &argc, argv, NULL, NULL);
  337.  
  338.     rowcol = XtVaCreateWidget("rowcolumn",
  339.         xmRowColumnWidgetClass, toplevel,
  340.         XmNpacking,        XmPACK_COLUMN,
  341.         XmNnumColumns,     XtNumber(text_labels),
  342.         XmNorientation,    XmHORIZONTAL,
  343.         XmNisAligned,      True,
  344.         XmNentryAlignment, XmALIGNMENT_END,
  345.         NULL);
  346.  
  347.     /* simply loop thru the strings creating a widget for each one */
  348.     for (i = 0; i < XtNumber(text_labels); i++) {
  349.         XtVaCreateManagedWidget(text_labels[i],
  350.             xmLabelGadgetClass, rowcol,
  351.             NULL);
  352.         sprintf(buf, "text_%d", i);
  353.         XtVaCreateManagedWidget(buf,
  354.             xmTextWidgetClass, rowcol,
  355.             NULL);
  356.     }
  357.  
  358.     XtManageChild(rowcol);
  359.     XtRealizeWidget(toplevel);
  360.     XtAppMainLoop(app);
  361. }
  362.  
  363. This makes all objects exactly the same size.  It does not resize in nice
  364. ways.
  365.  
  366. If you want the text widgets lined up on the left, and the labels to be the
  367. size of the longest string, resizing nicely both horizontally and vertically,
  368. as in
  369.  
  370.          -------------------------------------
  371.         |                    ---------------- |
  372.         |          a label  |Some text       ||
  373.         |                    ---------------- |
  374.                              ---------------- |
  375.         |   a longer label  |Some more text  ||
  376.         |                    ---------------- |
  377.         |                    ---------------- |
  378.         |a very long label  |Even more text  ||
  379.         |                    ---------------- |
  380.          -------------------------------------
  381.  
  382.  
  383.  
  384. Answer: Do this: to get the widgets lined up horizontally, use a form but
  385. place the widgets using XmATTACH_POSITION.  In the example, attach the top of
  386. the first label to the form, the bottomPosition to 33 (33% of the height).
  387. Attach the topPosition of the second label to 33 and the bottomPosition to 66.
  388. Attach the topPosition of the third label to 66 and the bottom of the label to
  389. the form.  Do the same with the text widgets.
  390.  
  391. To get the label widgets lined up vertically, use the right attachment of
  392. XmATTACH_OPPOSITE_WIDGET: starting from the one with the longest label, attach
  393. widgets on the right to each other. In the example, attach the 2nd label to
  394. the third, and the first to the second.  To get the text widgets lined up,
  395. just attach them on the left to the labels.  To get the text in the labels
  396. aligned correctly, use XmALIGNMENT_END for the XmNalignment resource.
  397.  
  398.         /* geometry for label 2
  399.         */
  400.         n = 0;
  401.         XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
  402.         XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  403.         XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  404.         XtSetArg (args[n], XmNtopAttachment, XmATTACH_POSITION); n++;
  405.         XtSetArg (args[n], XmNtopPosition, 66); n++;
  406.         XtSetValues (label[2], args, n);
  407.  
  408.         /* geometry for label 1
  409.         */
  410.         n = 0;
  411.         XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
  412.         XtSetArg (args[n], XmNbottomAttachment, XmATTACH_POSITION); n++;
  413.         XtSetArg (args[n], XmNbottomPosition, 66); n++;
  414.         XtSetArg (args[n], XmNtopAttachment, XmATTACH_POSITION); n++;
  415.         XtSetArg (args[n], XmNtopPosition, 33); n++;
  416.         XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  417.         XtSetArg (args[n], XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
  418.         XtSetArg (args[n], XmNrightWidget, label[2]); n++;
  419.         XtSetValues (label[1], args, n);
  420.  
  421.         /* geometry for label 0
  422.         */
  423.         n = 0;
  424.         XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
  425.         XtSetArg (args[n], XmNbottomAttachment, XmATTACH_POSITION); n++;
  426.         XtSetArg (args[n], XmNbottomPosition, 33); n++;
  427.         XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  428.         XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  429.         XtSetArg (args[n], XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
  430.         XtSetArg (args[n], XmNrightWidget, label[1]); n++;
  431.         XtSetValues (label[0], args, n);
  432.  
  433.         /* geometry for text 0
  434.         */
  435.         n = 0;
  436.         XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  437.         XtSetArg (args[n], XmNbottomAttachment, XmATTACH_POSITION); n++;
  438.         XtSetArg (args[n], XmNbottomPosition, 33); n++;
  439.         XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  440.         XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
  441.         XtSetArg (args[n], XmNleftWidget, label[0]); n++;
  442.         XtSetValues (text[0], args, n);
  443.  
  444.         /* geometry for text 1
  445.         */
  446.         XtSetArg (args[n], XmNtopAttachment, XmATTACH_POSITION); n++;
  447.         XtSetArg (args[n], XmNtopPosition, 33); n++;
  448.         XtSetArg (args[n], XmNbottomAttachment, XmATTACH_POSITION); n++;
  449.         XtSetArg (args[n], XmNbottomPosition, 66); n++;
  450.         XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  451.         XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
  452.         XtSetArg (args[n], XmNleftWidget, label[1]); n++;
  453.         XtSetValues (text[1], args, n);
  454.  
  455.         /* geometry for text 2
  456.         */
  457.         XtSetArg (args[n], XmNtopAttachment, XmATTACH_POSITION); n++;
  458.         XtSetArg (args[n], XmNtopPosition, 66); n++;
  459.         XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  460.         XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
  461.         XtSetArg (args[n], XmNleftWidget, label[2]); n++;
  462.         XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  463.         XtSetValues (text[2], args, n);
  464.  
  465.  
  466. -----------------------------------------------------------------------------
  467. Subject: 66)  TOPIC: PUSHBUTTON WIDGET
  468.  
  469. -----------------------------------------------------------------------------
  470. Subject: 67)  Why can't I use accelerators on buttons not in a menu?
  471.  
  472. Answer: It is apparently a difficult feature to implement, but OSF are
  473. considering this for the future. It is problematic trying to use the Xt
  474. accelerators since the Motif method interferes with this.  one workaround
  475. suggested is to duplicate your non-menu button by a button in a menu
  476. somewhere, which does have a menu-accelerator installed.  When the user
  477. invokes what they think is the accelerator for the button they can see Motif
  478. actually invokes the button on the menu that they can't see at the time.
  479. Another method is described below and was contributed by Harald Albrecht of
  480. Institute of Geometry and Practical Mathematics Rhine Westphalia Technical
  481. University Aachen (RWTH Aachen), Germany
  482.  
  483.  
  484. From albrecht@igpm.rwth-aachen.de Thu Jul  8 11:44:21 1993
  485.  
  486. My work-around of this problem looks like this: (I've written that code for a
  487. Motif Object Library in C++ so please forgive me for being object orientated!)
  488. The hack consists of a rewritten message loop which checks for keypresses
  489. <MAlt>+<key>. If MessageLoop() finds such a keypress HandleAcc() ist called
  490. and the widget tree is searched for a suitable widget with the right mnemonic.
  491.  
  492.  
  493. // --------------------------------------------------------------------------
  494. // traverse the widget tree starting with the given widget.
  495. //
  496. BOOL TraverseWidgetTree(Widget w, char *pMnemonic, XKeyEvent *KeyEvent)
  497. {
  498.     Widget               wChild;
  499.     WidgetList           ChildList;
  500.     int                  NumChilds, Child;
  501.     KeySym               LabelMnemonic;
  502.     char                 *pMnemonicString;
  503.  
  504. // Check if the widget is a subclass of label -- then it may have an
  505. // accelerator attached...
  506.     if ( XtIsSubclass(w, xmLabelWidgetClass) ) {
  507. // ok. Now: get the widget's mnemonic, convert it to ASCII and compare
  508. // it with the Key we're looking for.
  509.         XtVaGetValues(w, XmNmnemonic, &LabelMnemonic, NULL);
  510.         pMnemonicString = XKeysymToString(LabelMnemonic);
  511.         if ( pMnemonicString &&
  512.              (strcasecmp(pMnemonicString, pMnemonic) == 0) ) {
  513.             // stimulate the keypress
  514.             XmProcessTraversal((Widget)w, XmTRAVERSE_CURRENT);
  515.             KeyEvent->type      = KeyPress;
  516.             KeyEvent->window    = XtWindow(w);
  517.             KeyEvent->subwindow = XtWindow(w);
  518.             KeyEvent->state     = 0;
  519.             KeyEvent->keycode   =
  520.                 XKeysymToKeycode(XtDisplay(w), XK_space);
  521.             XSendEvent(XtDisplay(w), XtWindow(w),
  522.                        True,
  523.                        ButtonPressMask, (XEvent*) KeyEvent);
  524.             KeyEvent->type      = KeyRelease;
  525.             XSendEvent(XtDisplay(w), XtWindow(w),
  526.                        True,
  527.                        ButtonReleaseMask, (XEvent*) KeyEvent);
  528.             return True;
  529.         }
  530.     }
  531. // if this widget is a subclass of Composite check all the widget's
  532. // childs.
  533.     if ( XtIsSubclass(w, compositeWidgetClass) ) {
  534. // if we're in a menu (or something like that) forget this leaf of the
  535. // widget tree!
  536.         if ( XtIsSubclass(w, xmRowColumnWidgetClass) ) {
  537.             unsigned char RowColumnType;
  538.             XtVaGetValues(w, XmNrowColumnType, &RowColumnType, NULL);
  539.             if ( RowColumnType != XmWORK_AREA ) return False;
  540.         }
  541.         XtVaGetValues(w, XmNchildren, &ChildList,
  542.                          XmNnumChildren, &NumChilds, NULL);
  543.         for ( Child = 0; Child < NumChilds; ++Child ) {
  544.             wChild = ChildList[Child];
  545.             if ( TraverseWidgetTree(wChild, pMnemonic, KeyEvent) )
  546.                 return True;
  547.         }
  548.     }
  549.     return False;
  550. } // TraverseWidgetTree
  551. // --------------------------------------------------------------------------
  552. // handle accelerators (keypress MAlt + key)
  553. //
  554. #define MAX_MAPPING 10
  555. BOOL HandleAcc(Widget w, XEvent *event)
  556. {
  557.            Widget         widget, OldWidget;
  558.     static char           keybuffer[MAX_MAPPING];
  559.            int            CharCount;
  560.     static XComposeStatus composeStatus;
  561.  
  562. // convert KeyPress to ASCII
  563.     CharCount = XLookupString((XKeyEvent*) event,
  564.                               keybuffer, sizeof(keybuffer),
  565.                               NULL, &composeStatus);
  566.     keybuffer[CharCount] = 0;
  567. // Only one char is alright -- then search the widget tree for a widget
  568. // with the right mnemonic
  569.     if ( CharCount == 1 ) {
  570.         keybuffer[0] = tolower(keybuffer[0]);
  571.         widget = w;
  572.         while ( (widget != NULL) &&
  573.                 !XtIsSubclass(widget, shellWidgetClass) ) {
  574.             OldWidget = widget; widget = XtParent(widget);
  575.         }
  576.         if ( !widget ) widget = OldWidget;
  577.         return TraverseWidgetTree(widget,
  578.                                   keybuffer, (XKeyEvent*) event);
  579.     }
  580.     return False; // no-one found.
  581. } // HandleAcc
  582. // --------------------------------------------------------------------------
  583. // modified message loop
  584. // loops until the Boolean pFlag points to is set to False
  585. void MessageLoop(Boolean *pFlag)
  586. {
  587.     XEvent nextEvent;
  588.  
  589.     while ( *pFlag ) {
  590.         if ( XtAppPending(AppContext) ) {
  591.             XtAppNextEvent(AppContext, &nextEvent);
  592.             if ( nextEvent.type == KeyPress ) {
  593. // Falls es ein Tastendruck ist, bei dem auch noch die ALT-Taste
  594. // (=Modifier 1) gedrueckt ist, koennte es ein Accelerator sein!
  595.                 if ( nextEvent.xkey.state & Mod1Mask )
  596.                     if ( HandleAcc(XtWindowToWidget(nextEvent.xkey.display,
  597.                                                     nextEvent.xkey.window),
  598.                                    &nextEvent) )
  599.                         continue; // Mitteilung konnte ausgeliefert werden
  600.                                   // und darf daher nicht den ueblichen
  601.                                   // Weg gehen!
  602.             }
  603.             XtDispatchEvent(&nextEvent);
  604.         }
  605.     }
  606. } // TApplication::MessageLoop
  607.  
  608.  
  609. Harald Albrecht albrecht@igpm.rwth-aachen.de Institute of Geometry and
  610. Practical Mathematics Rhine Westphalia Technical University Aachen (RWTH
  611. Aachen), Germany
  612.  
  613.  
  614. -----------------------------------------------------------------------------
  615. Subject: 68)  TOPIC: LABEL WIDGET
  616.  
  617. -----------------------------------------------------------------------------
  618. Subject: 69)  How can I align the text in a label (button, etc) widget?
  619.  
  620. Answer: The alignment for the label widget is controlled by the resource
  621. XmNalignment, and the default centers the text. Use this resource to change it
  622. to left or right alignment.  However, when the label (or any descendant) is in
  623. a row column, and XmNisAligned is True (the default), the row column aligns
  624. text using its resource XmNentryAlignment. If you want simultaneous control
  625. over all widgets use this, but otherwise turn XmNisAligned off and do it
  626. individually.
  627.  
  628.  
  629.  
  630. -----------------------------------------------------------------------------
  631. Subject: 70)  Why doesn't label alignment work in a RowColumn?
  632.  
  633. Answer: RowColumn has a  resource XmNisAligned (default True) and and
  634. XmNentryAlignment (default XmALIGNMENT_BEGINNING).  These control alignment of
  635. the labelString in Labels and descendants. Set XmNisAligned to False to turn
  636. this off.
  637.  
  638. -----------------------------------------------------------------------------
  639. Subject: 71)  How can I set a multiline label?
  640. [Last modified: September 92]
  641.  
  642. Answer: In .Xdefaults
  643.  
  644.       *XmLabel*labelString:             Here\nis\nthe\nLabel
  645.  
  646. This method does not seem to work in some of the older Motif 1.0 versions.
  647.  
  648. In code,
  649.  
  650.       char buf[128];
  651.       XmString msg;
  652.       sprintf(buf, "Here\nis\nthe\nLabel");
  653.       msg = XmStringCreateLtoR(buf, XmSTRING_DEFAULT_CHARSET);
  654.       XtSetArg (args[n], XmNlabelString, msg);
  655.  
  656. Gives a four line label, using the escape sequence \n for a newline.  However,
  657. XmStringCreateLtoR() is obsoleted from version 1.1 on, and may disappear.
  658. This is because it it is only in the AES as "trial-use" and has been proposed
  659. for removal from the AES. Realistically, it will probably not be removed from
  660. any backward compatible versions of Motif, but the potential is there.  If it
  661. does disappear (or if you want to avoid using the non-AES compliant
  662. XmSTRING_DEFAULT_CHARSET), try this from Jean-Philippe Martin-Flatin
  663. <syj@ecmwf.co.uk>
  664.  
  665. #include <Xm/Xm.h>
  666. #include <string.h>
  667.  
  668. /*-----------------------------------------------------
  669.     Create a new XmString from a char*
  670.  
  671.     This function can deal with embedded 'newline' and
  672.     is equivalent to the obsolete XmStringCreateLtoR,
  673.     except it does not use non AES compliant charset
  674.     XmSTRING_DEFAULT_CHARSET
  675. ----------------------------------------------------*/
  676. XmString xec_NewString(char *s)
  677. {
  678.     XmString xms1;
  679.     XmString xms2;
  680.     XmString line;
  681.     XmString separator;
  682.     char     *p;
  683.     char     *t = XtNewString(s);   /* Make a copy for strtok not to */
  684.                                     /* damage the original string    */
  685.  
  686.  
  687.     separator = XmStringSeparatorCreate();
  688.     p         = strtok(t,"\n");
  689.     xms1      = XmStringCreateSimple(p);
  690.  
  691.     while (p = strtok(NULL,"\n"))
  692.     {
  693.         line = XmStringCreateSimple(p);
  694.         xms2 = XmStringConcat(xms1,separator);
  695.         XmStringFree(xms1);
  696.         xms1 = XmStringConcat(xms2,line);
  697.         XmStringFree(xms2);
  698.         XmStringFree(line);
  699.     }
  700.  
  701.     XmStringFree(separator);
  702.     XtFree(t);
  703.     return xms1;
  704. }
  705.  
  706.  
  707. Do not use XmStringCreateSimple() - it does not process the newline character
  708. in the way you want.
  709.  
  710. In UIL, you have to explicitly create a compound string with a separator.
  711. Here's what W. Scott Meeks suggests:
  712.  
  713. value nl : compound_string('', seperate=true);
  714.  
  715. object my_label : XmLabel
  716. {
  717.     arguments
  718.     {
  719.         XmNlabelString = 'Here' & nl & 'is' & nl & 'the' & nl & 'Label';
  720.     };
  721. };
  722.  
  723.  
  724. -----------------------------------------------------------------------------
  725. Subject: 72)  How can I have a vertical label?
  726.  
  727. Answer: Make a multiline label with one character per line, as in the last
  728. question. There is no way to make the text rotated by 90 degrees though.
  729.  
  730.  
  731. -----------------------------------------------------------------------------
  732. Subject: 73)  How can I have a Pixmap in a Label?
  733.  
  734. Answer: From Bob Hays (bobhays@spss.com)
  735.  
  736.     Pixmap px_disarm, px_disarm_insens;
  737.  
  738.     Widget Label1;
  739.     Pixel   foreground, background;
  740.     Arg     args[4];
  741.     Arg     arg[] = {
  742.                 { XmNforeground, &foreground },
  743.                 { XmNbackground, &background }
  744.     };
  745.  
  746.     Label1 = XmCreateLabel ( Shell1, "Label1",
  747.                                        (Arg *) NULL, (Cardinal) 0 );
  748.     XtGetValues ( Label1, arg, XtNumber ( arg ) );
  749.     px_disarm =
  750.       XCreatePixmapFromBitmapData(display,
  751.                                 DefaultRootWindow(display),
  752.                                 mtn_bits, mtn_width, mtn_height,
  753.                                 foreground,
  754.                                 background,
  755.                                 DefaultDepth(display,DefaultScreen(display)));
  756.     px_disarm_insens =
  757.       XCreatePixmapFromBitmapData(display,
  758.                                 DefaultRootWindow(display),
  759.                                 mtn_ins_bits, mtn_ins_width, mtn_ins_height,
  760.                                 foreground,
  761.                                 background,
  762.                                 DefaultDepth(display,DefaultScreen(display)));
  763.  
  764.     n = 0;
  765.     XtSetArg(args[n], XmNlabelType, XmPIXMAP);  n++;
  766.     XtSetArg(args[n], XmNlabelPixmap, px_disarm);  n++;
  767.     XtSetArg(args[n], XmNlabelInsensitivePixmap, px_disarm_insens ); n++;
  768.     XtSetValues ( Label1, args, n );
  769.     XtManageChild(Label1);
  770.  
  771. That will cause the foreground and background of your pixmap to be inherited
  772. from the one that would be used by OSF/Motif when the label is displayed.  The
  773. advantage is that this will utilize any resource values the user may have
  774. requested without looking explicitly into the resource database.  And, you
  775. will have a pixmap handy if the application insensitizes the label (without an
  776. XmNlabelInsensitivePixmap your label will go empty if made insensitive).
  777.  
  778. [Bob's original code was for a PushButton. Just change all Label to PushButton
  779. for them.]
  780.  
  781.  
  782. -----------------------------------------------------------------------------
  783. Subject: 74)  TOPIC: DRAWING AREA WIDGET
  784.  
  785. -----------------------------------------------------------------------------
  786. Subject: 75)  How can I send an expose event to a Drawing Area widget?  (or
  787. any other, come to that). I want to send an expose event so that it will
  788. redraw itself.
  789.  
  790. Answer: Use the Xlib call
  791.  
  792.         XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, True)
  793.  
  794. This clears the widget's window and generates an expose event in doing so.
  795. The widgets expose action will then redraw it.  This uses a round trip
  796. request.  An alternative, without the round trip is
  797.  
  798. from orca!mesa!rthomson@uunet.uu.net  (Rich Thomson):
  799.  
  800.     Widget da;
  801.     XmDrawingAreaCallbackStruct da_struct;
  802.  
  803.     da_struct.reason = XmCR_EXPOSE;
  804.     da_struct.event = (XEvent *) NULL;
  805.     da_struct.window = XtWindow(da);
  806.  
  807.     XtCallCallbacks(da, XmNexposeCallback, (XtPointer) da_struct);
  808.  
  809.  
  810. -----------------------------------------------------------------------------
  811. Subject: 76)  How can I know when a DrawingArea has been resized?  It
  812. generates an expose event whn it is enlarged, but not when it is shrunk.
  813.  
  814. Answer: Use the resize callback.
  815.  
  816. -----------------------------------------------------------------------------
  817. Subject: 77)  TOPIC: MENUS
  818.  
  819. -----------------------------------------------------------------------------
  820. Subject: 78)  What can I put inside a menu bar?
  821.  
  822. Answer: You can only put cascade buttons in menu bars. No pushbuttons, toggle
  823. buttons or gadgets are allowed. When you create a pulldown menu with parent a
  824. menu bar, its real parent is a shell widget.
  825.  
  826. -----------------------------------------------------------------------------
  827. Subject: 79)  Can I have a cascade button without a submenu in a pulldown
  828. menu?
  829.  
  830. Answer: Yes you can. A cascade button has an activate callback which is called
  831. when you click on it and it doesn't have a submenu. It can have a mnemonic,
  832. but keyboard traversal using the arrow keys in the menu will skip over it.
  833.  
  834. -----------------------------------------------------------------------------
  835. Subject: 80)  Should I have a cascade button without a submenu in a pulldown
  836. menu?
  837.  
  838. Answer: No. This is forbidden by the style guide. Technically you can do it
  839. (see previous question) but if you do it will not be Motif style compliant.
  840. This is unlikely to change - if a "button" is important enough to be in a
  841. pulldown menu bar with no pulldown, it should be a button elsewhere.  (Mind
  842. you, you won't be able to put accelerators on it elsewhere though.)
  843.  
  844. -----------------------------------------------------------------------------
  845. Subject: 81)  What is the best way to create popup menus?
  846. [Last modified: August 92]
  847.  
  848. Susan Murdock Thompson (from OSF): In general, create a popupMenu as the child
  849. from which you will be posting it from (ie: if you have a bulletinBoard with a
  850. PushButton in it and want MB2 on the pushButton to post the popupMenu, create
  851. the popupMenu as a child of the pushButton).  [This parent-child relationship
  852. seems to make a big difference in the behavior of the popups.]  Add an event
  853. handler to handle buttonPress events.  You'll need to check for the correct
  854. button (what you've specified menuPost to be) before posting the menu.
  855.  
  856. To create a popup that can be accessible from within an entire client window,
  857. create it as the child of the top-most widget (but not the shell) and add
  858. event handlers for the top-most widget and children widgets.
  859.  
  860. ie:
  861.  
  862. {
  863.   ....
  864.  
  865.   XtManageChild(rc=XmCreateRowColumn(Shell1, "rc", NULL, 0));
  866.   XtManageChild(label = XmCreateLabel(rc, "label", NULL, 0));
  867.   XtManageChild(text = XmCreateText(rc, "text", NULL, 0));
  868.   XtManageChild(pushbutton = XmCreatePushButton(rc, "pushbutton", NULL, 0));
  869.  
  870.   n = 0;
  871.   XtSetArg(args[n], XmNmenuPost, "<Btn3Down>"); n++;
  872.   popup = XmCreatePopupMenu(rc, "popup", args, n);
  873.  
  874.   XtAddEventHandler(rc, ButtonPressMask, False, PostMenu3, popup);
  875.   XtAddEventHandler(text, ButtonPressMask, False, PostMenu3, popup);
  876.   XtAddEventHandler(label, ButtonPressMask, False, PostMenu3, popup);
  877.   XtAddEventHandler(pushbutton, ButtonPressMask, False, PostMenu3, popup);
  878.  
  879.   XtManageChild(m1 = XmCreatePushButton(popup, "m1", NULL, 0));
  880.   XtManageChild(m2 = XmCreatePushButton(popup, "m2", NULL, 0));
  881.   XtManageChild(m3 = XmCreatePushButton(popup, "m3", NULL, 0));
  882.  
  883.   XtAddCallback(m1, XmNactivateCallback, SayCB, "button M1");
  884.   XtAddCallback(m2, XmNactivateCallback, SayCB, "button M2");
  885.   XtAddCallback(m3, XmNactivateCallback, SayCB, "button M3");
  886.   ...
  887. }
  888.  
  889. /* where PostMenu3 is ... */
  890.  
  891. PostMenu3 (w, popup, event)
  892. Widget w;
  893. Widget popup;
  894. XButtonEvent * event;
  895. {
  896.   printf("menuPost = 3, button %d0, event->button);
  897.  
  898.   if (event->button != Button3)
  899.     return;
  900.   XmMenuPosition(popup, event);
  901.   XtManageChild(popup);
  902. }
  903.  
  904.  
  905.  
  906. -----------------------------------------------------------------------------
  907. Subject: 82)  How do popup menus work?
  908. [Last modified: August 92]
  909.  
  910. Answer:
  911.  
  912. When a popup menu is created as the child of a widget the menu system installs
  913. a translation on the parent of the popup and descendants with an action which:
  914. (1) when 3-rd button (the default for the menuPost resource) is pressed the
  915. cursor changes and the mouse is grabbed for 5 seconds; (2) disables event
  916. handlers on the descendants and the handlers are never called; (3) an event
  917. handler installed on the parent works fine.
  918.  
  919. It is done so that the correct event handler will (in fact) be called.  There
  920. is a grab with owner_events true.  The grab is released by a timer,  but
  921. normally the posted menu shell puts up it's own grab.
  922.  
  923. If you only have widgets then you can use the subwindow field in the event to
  924. identify the original widget.  If you have gadgets or other data that you want
  925. to change the menu for (or use a specific menu for) then you must do a walk of
  926. the parent's children to find the best match.
  927.  
  928. One thing to beware of is that even with the grab,  because the menu system
  929. does a grab with owner events true, you must either have an event handler, or
  930. nothing that will use the event on each widget in the hierarchy of the menu's
  931. parent.  If a child widget has another event handler for button down, it may
  932. swallow the event and do something else.
  933.  
  934.  
  935.  
  936. -----------------------------------------------------------------------------
  937. Subject: 83)  Should I use translation tables or actions for popup menus?
  938. [Last modified: August 92]
  939.  
  940. Answer: The original goal of popupMenus was that the user would not have to
  941. specify an event handler to manage popupMenus; however, that did not become
  942. reality.  Larry Rogers wrote:
  943.  
  944. > There appear to be two ways to manage popup menus.  I
  945. > am curious what the correct way would be:
  946.  
  947. > 1.  Change the translation table of the widget with the
  948. >    popup child to popup the menu.  Note that this does
  949. >    not currently working for many widgets, because aug-
  950. >    menting their translations, even for augment breaks
  951. >    the widget.
  952.  
  953. > 2.  Add an event handler at creation to the widget; then
  954. >    determine if the event that caused the event handler
  955. >    to be called is the current button being used by the
  956. >    menu as its activation button.
  957.  
  958. Susan Murdock Thompson (from OSF) replied: *Theoretically, you should be able
  959. to do both.*  Our documentation says use event handlers.  Our tests for the
  960. toolkit use event handlers and for UIL use translations.  (Although I tried an
  961. event handler with a UIL test and it works).
  962.  
  963. -----------------------------------------------------------------------------
  964. Subject: 84)  What are the known bugs in popup menus?
  965. [Last modified: August 92]
  966.  
  967. Answer: As at Motif 1.1.4, the bugs for which an OSF PIR exists are:
  968.  
  969.    (3)  Menus not being sticky (ie: posted on a Btn CLICK)  [ Note:this
  970.         problem occurs with OptionMenus as well]  (PIR 3435)
  971.  
  972.    (6)  Destroying a widget with an associated popupMenu results in
  973.         "Warning: Attempt to remove non-existant passive grab"         (PIR
  974. 2972)
  975.  
  976.    (7)  Current documentation insufficient regarding requirements for
  977.         success in using PopupMenus.  (PIR 3433)
  978.  
  979.  
  980. -----------------------------------------------------------------------------
  981. Subject: 85)  Can I have multiple popup menus on the same widget?
  982. [Last modified: August 92]
  983.  
  984. Answer: If you want to have several popups (activated by different mouse
  985. buttons) on the same widget..., well, that doesn't work yet.
  986.  
  987. If you want to have several popups on different children... that works.  But
  988. don't put a popup on the parent (manager) widget, or it will rule!
  989.  
  990.  
  991.  
  992. -----------------------------------------------------------------------------
  993. Subject: 86)  TOPIC: INPUT FOCUS
  994.  
  995. -----------------------------------------------------------------------------
  996. Subject: 87) How can I specify the widget that should have the keyboard focus
  997. when my application starts up?  Answer: In Motif 1.2, use XmNinitialFocus on
  998. the manager widget.  thanks to Ken Lee, klee@synoptics.com
  999.  
  1000.  
  1001. -----------------------------------------------------------------------------
  1002. Subject: 88)  How can I direct the keyboard input to a particular widget?
  1003.  
  1004. Answer: In Motif 1.1 call XmProcessTraversal(target, XmTRAVERSE_CURRENT).  The
  1005. widget (and all of its ancestors) does need to be realized BEFORE you call
  1006. this. Otherwise it has no effect.  XmProcessTraversal is reported to have many
  1007. bugs, so it may not work right.  A common occurrence is that it doesn't move
  1008. to the widget, but if you call XmProcessTraversal *twice* in a row, it will.
  1009. If you can't get it to work, try this from Kee Hinckley:
  1010.  
  1011.     // This insane sequence is as follows:
  1012.     //      On manage set up a focus callback
  1013.     //      On focus callback set up a timer (and get rid of focus callback!)
  1014.     //      On timer set the focus (which only works if the parent
  1015.     //      has the focus,
  1016.     //      which is why we went through all of this garbage)
  1017.     // There may be a better way, but I haven't time to try it now.
  1018.     //
  1019.     static void focusTO(void *data, XtIntervalId *) {
  1020.         XmProcessTraversal((Widget) data, XmTRAVERSE_CURRENT);
  1021.     }
  1022.  
  1023.     static void focusCB(Widget w, XtPointer data, XtPointer) {
  1024.         XtRemoveCallback(w, XmNfocusCallback, focusCB, data);
  1025.         XtAppAddTimeOut(XtWidgetToApplicationContext(w), 0, focusTO, data);
  1026.     }
  1027.  
  1028.     void OmXSetFocus(Widget parent, Widget w) {
  1029.         XtAddCallback(parent, XmNfocusCallback, focusCB, w);
  1030.     }
  1031.  
  1032.  
  1033. In Motif 1.0 call the undocumented _XmGrabTheFocus(target).
  1034.  
  1035. Do not use the X or Xt calls such as XtSetKeyboardFocus since this bypasses
  1036. the Motif traversal layer and can cause it to get confused.  This can lead to
  1037. odd keyboard behaviour elsewhere in your application.
  1038.  
  1039. -----------------------------------------------------------------------------
  1040. Subject: 89)  How can I have a modal dialog which has to be answered before
  1041. the application can continue?
  1042. [Last modified: July 92]
  1043.  
  1044. Answer: The answer depends on whether you are using the Motif window manager
  1045. mwm or not.  Test for this by XmIsMotifWMRunning.
  1046.  
  1047. The window manager mwm knows how to control event passing to dialog widgets
  1048. declared as modal. If the dialog is set to application modal, then no
  1049. interaction with the rest of the application can occur until the dialog is
  1050. destroyed or unmanaged.
  1051.  
  1052. Use the appropriate code in the following program.  There is followup
  1053. discussion after the program.
  1054.  
  1055.  
  1056. /* Written by Dan Heller.  Copyright 1991, O'Reilly && Associates.
  1057.  * This program is freely distributable without licensing fees and
  1058.  * is provided without guarantee or warranty expressed or implied.
  1059.  * This program is -not- in the public domain.  This program is
  1060.  * taken from the Motif Programming Manual, O'Reilly Volume 6.
  1061.  */
  1062.  
  1063. /*
  1064.  * ask_user.c -- create a pushbutton that posts a dialog box
  1065.  * that asks the user a question that requires an immediate
  1066.  * response.  The function that asks the question actually
  1067.  * posts the dialog that displays the question, waits for and
  1068.  * returns the result.
  1069.  */
  1070. #include <X11/Intrinsic.h>
  1071. #include <Xm/DialogS.h>
  1072. #include <Xm/SelectioB.h>
  1073. #include <Xm/RowColumn.h>
  1074. #include <Xm/MessageB.h>
  1075. #include <Xm/PushBG.h>
  1076. #include <Xm/PushB.h>
  1077.  
  1078. XtAppContext app;
  1079.  
  1080. #define YES 1
  1081. #define NO  2
  1082.  
  1083. /* main() --create a pushbutton whose callback pops up a dialog box */
  1084. main(argc, argv)
  1085. char *argv[];
  1086. int argc;
  1087. {
  1088.     Widget parent, button, toplevel;
  1089.     XmString label;
  1090.     void pushed();
  1091.  
  1092.     toplevel = XtAppInitialize(&app, "Demos",
  1093.         NULL, 0, &argc, argv, NULL, NULL, 0);
  1094.  
  1095.     label = XmStringCreateSimple("/bin/rm *");
  1096.     button = XtVaCreateManagedWidget("button",
  1097.         xmPushButtonWidgetClass, toplevel,
  1098.         XmNlabelString,          label,
  1099.         NULL);
  1100.     XtAddCallback(button, XmNactivateCallback,
  1101.         pushed, "Remove Everything?");
  1102.     XmStringFree(label);
  1103.  
  1104.     XtRealizeWidget(toplevel);
  1105.     XtAppMainLoop(app);
  1106. }
  1107.  
  1108. /* pushed() --the callback routine for the main app's pushbutton. */
  1109. void
  1110. pushed(w, question)
  1111. Widget w;
  1112. char *question;
  1113. {
  1114.     if (AskUser(w, question) == YES)
  1115.         puts("Yes");
  1116.     else
  1117.         puts("No");
  1118. }
  1119.  
  1120. /*
  1121.  * AskUser() -- a generalized routine that asks the user a question
  1122.  * and returns the response.
  1123.  */
  1124. AskUser(parent, question)
  1125. char *question;
  1126. {
  1127.     static Widget dialog;
  1128.     XmString text, yes, no;
  1129.     static int answer;
  1130.     extern void response();
  1131.  
  1132.     answer = 0;
  1133.     if (!dialog) {
  1134.         dialog = XmCreateQuestionDialog(parent, "dialog", NULL, 0);
  1135.         yes = XmStringCreateSimple("Yes");
  1136.         no = XmStringCreateSimple("No");
  1137.         XtVaSetValues(dialog,
  1138.             XmNdialogStyle,        XmDIALOG_APPLICATION_MODAL,
  1139.             XmNokLabelString,      yes,
  1140.             XmNcancelLabelString,  no,
  1141.             NULL);
  1142.         XtSetSensitive(
  1143.             XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON), False);
  1144.         XtAddCallback(dialog, XmNokCallback, response, &answer);
  1145.         XtAddCallback(dialog, XmNcancelCallback, response, &answer);
  1146.         /* if the user interacts via the system menu: */
  1147.         XtAddCallback(dialog, XmNpopdownCallback, response, &answer);
  1148.     }
  1149.     text = XmStringCreateSimple(question);
  1150.     XtVaSetValues(dialog,
  1151.         XmNmessageString,      text,
  1152.         NULL);
  1153.     XmStringFree(text);
  1154.     XtManageChild(dialog);
  1155.     XtPopup(XtParent(dialog), XtGrabNone);
  1156.  
  1157.     /* while the user hasn't provided an answer, simulate XtMainLoop.
  1158.      * The answer changes as soon as the user selects one of the
  1159.      * buttons and the callback routine changes its value.  Don't
  1160.      * break loop until XtPending() also returns False to assure
  1161.      * widget destruction.
  1162.      */
  1163.     while (answer == 0 || XtAppPending(app))
  1164.         XtAppProcessEvent(app, XtIMAll);
  1165.     return answer;
  1166. }
  1167.  
  1168. /* response() --The user made some sort of response to the
  1169.  * question posed in AskUser().  Set the answer (client_data)
  1170.  * accordingly and destroy the dialog.
  1171.  */
  1172. void
  1173. response(w, answer, reason)
  1174. Widget w;
  1175. int *answer;
  1176. XmAnyCallbackStruct *reason;
  1177. {
  1178.     switch (reason->reason) {
  1179.         case XmCR_OK:
  1180.             *answer = YES;
  1181.             break;
  1182.         case XmCR_CANCEL:
  1183.             *answer = NO;
  1184.             break;
  1185.         default:
  1186.             *answer = NO;
  1187.             return;
  1188.     }
  1189. }
  1190.  
  1191.  
  1192.  
  1193. If you aren't running a window manager that acknowledges this hint, then you
  1194. may have to grab the pointer (and keyboard) yourself to make sure the user
  1195. doesn't interact with any other widget.  Change the grab flag in XtPopup to
  1196. XtGrabExclusive, and XtRemoveGrab(XtParent(w)) to the response() function.
  1197.  
  1198.  
  1199. -----------------------------------------------------------------------------
  1200. Subject: 90)  TOPIC: MEMORY AND SPEED
  1201.  
  1202. -----------------------------------------------------------------------------
  1203. Subject: 91)  When can I free data structures passed to or retrieved from
  1204. Motif?
  1205.  
  1206. Answer:
  1207.  In most cases, especially for XmStrings and XmFontLists, Motif copies data
  1208. passed to it or retrieved from it, so it may be freed immediately.  Server-
  1209. side resources, such as pixmaps and color cells, however, are not copied, so
  1210. should not be freed.  More recent versions of Motif are better than earlier
  1211. versions and exceptions should be documented.  thanks to klee*synoptics.com
  1212. (Ken Lee)
  1213.  
  1214. -----------------------------------------------------------------------------
  1215. Subject: 92)  Why does my application grow in size?
  1216.  
  1217. Answer: Motif 1.0 has many memory leaks, particularly in XmString
  1218. manipulation.  Switch to Motif 1.1.
  1219.  
  1220. Answer: The Intrinsics have a memory leak in accelerator table management, and
  1221. Motif uses this heavily.  Avoid this by mapping/unmapping widgets rather than
  1222. creating/destroying them, or get  X11R4 fix-15/16/17.
  1223.  
  1224. Answer: The server may grow in size due to its own memory leaks.  Switch to a
  1225. later server.
  1226.  
  1227. Answer: You are responsible for garbage collection in `C'.  Some common cases
  1228. where a piece of memory becomes garbage are
  1229.  
  1230.  a.  Memory is allocated by Motif for XmStrings by the functions
  1231.      XmStringConcat, XmStringCopy, XmStringCreate, XmStringCreateLtoR,
  1232.      XmStringCreateSimple, XmStringDirectionCreate, XmStringNConcat,
  1233.      XmStringNCopy, XmStringSegmentCreate, and XmStringSeparatorCreate.  The
  1234.      values returned by these functions should be freed using XmStringFree
  1235.      when they are no longer needed.
  1236.  
  1237.  b.  Memory is allocated by Motif for ordinary character strings (of type
  1238.      String) by Motif in XmStringGetLtoR, XmStringGetNextComponent, and
  1239.      XmStringGetNextSegment. After using the string, XtFree() it. [Note that
  1240.      XmStrings and Strings are two different data types.  XmStrings are
  1241.      XmStringFree'd, Strings are XtFree'd.]
  1242.  
  1243.  c.  If you have set the label (an XmString) in a label, pushbutton, etc
  1244.      widget, free it after calling XtSetValues() or the widget creation
  1245.      routine by XmStringFree().
  1246.  
  1247.  d.  If you have set text in a text widget, the text widget makes its own
  1248.      copy.  Unless you have a use for it, there is no need to keep your own
  1249.      copy.
  1250.  
  1251.  e.  If you have set the strings in a list widget the list widget makes its
  1252.      own copy.  Unless you have a use for it, there is no need to keep your
  1253.      own copy.
  1254.  
  1255.  f.  When you get the value of a single compound string from a Widget e.g.
  1256.      XmNlabelString, XmNmessageString, ... Motif gives you a copy of its
  1257.      internal value.  You should XmStringFree this when you have finished with
  1258.      it.
  1259.  
  1260.  g.  On the other hand, when you get a value of a Table e.g. XmStringTable for
  1261.      a List, you get a *pointer* to the internal Table, and should not free
  1262.      it.
  1263.  
  1264.  h.  When you get the value of the text in a widget by XmTextGetString or from
  1265.      the resource XmNvalue, you get a copy of the text.  You should XtFree
  1266.      this when you have finished with it.
  1267.  
  1268. Answer: From Josef Nelissen: at least in Motif 1.1.4, X11R4 on a HP 720, the
  1269. XmText/XmTextFieldSetString() functions have a memory leak.  The old
  1270. value/contents of the Widget isn't freed correctly.  To work around this bug,
  1271. one should use a XmText Widget (in single-line-mode) instead of a XmTextField
  1272. Widget (the solution fails with XmTextField Widgets !) and replace any
  1273.  
  1274.        XmTextSetString(text_widget, str);
  1275.  
  1276. by
  1277.  
  1278.        XmTextReplace(text_widget, (XmTextPosition) 0,
  1279.                      XmTextGetLastPosition(text_widget), str);
  1280.  
  1281.  
  1282. -----------------------------------------------------------------------------
  1283. Subject: 93)  Why does my application take a long time to start up?
  1284.  
  1285. Answer: You are probably creating too many widgets at startup time.  Delay
  1286. creating them until needed.  If you have a large number of resources in text
  1287. files (such as in app-defaults), time may be spent reading and parsing it.
  1288.  
  1289. -----------------------------------------------------------------------------
  1290. Subject: 94)  My application is running too slowly. How can I speed it up?
  1291.  
  1292. Answer: Use the R4 rather than R3 server.  It is much faster.
  1293.  
  1294. Answer: The standard memory allocator is not well tuned to Motif, and can
  1295. degrade performance.  Use a better allocator.  e.g. with SCO Unix, link with
  1296. libmalloc.a; use the allocator from GNU emacs; use the allocator from Perl.
  1297.  
  1298. Answer: Avoid lots of widget creation and destruction.  It fragments memory
  1299. and slows everything down.  Popup/popdown, manage/unmanage instead.
  1300.  
  1301. Answer: Set mappedWhenManaged to FALSE, and then call XtMapWidget()
  1302. XtUnmapWidget() rather than managing.
  1303.  
  1304. Answer: Get more memory - your application, the server and the Operating
  1305. System may be spending a lot of time being swapped.
  1306.  
  1307. Answer: If you are doing much XmString work yourself, such as heavy use of
  1308. XmStringCompare, speed may deteriorate due to the large amount of internal
  1309. conversions and malloc'ing.  Try using XmStringByteCompare if appropriate or
  1310. ordinary Ascii strings if you can.
  1311.  
  1312.  
  1313.  
  1314. -----------------------------------------------------------------------------
  1315. Subject: 95)  Why is my application so huge?
  1316.  
  1317. Answer: The typical size of a statically linked Motif app is in the megabytes.
  1318. This is often caused by the size of libXm.a. A large part of this gets linked
  1319. in to even trivial Motif programs. You can reduce the code size by linking
  1320. against shared libraries if they are available.  Running "strip" on the
  1321. executable can often reduce size. Note that the size of the running program
  1322. should be measured by "ps", not by the code size.
  1323.  
  1324. -----------------------------------------------------------------------------
  1325. END OF PART THREE
  1326. -- 
  1327. ..........................
  1328.  
  1329.